﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Json_Test.SerializeClasses;
using ComputerBeacon.Json;
using System.Collections.Generic;

namespace Json_Test {
    [TestClass]
    public class Serialize {

        #region Verify serialize classes
        void Verify(Address a, JsonObject jo) {
            Assert.AreEqual(a.CountryField, jo["CountryField"]);
            Assert.AreEqual(a.StateField, jo["StateField"]);
        }


        void Verify(User u, JsonObject jo) {
            Assert.AreEqual(u.NameProperty, jo["NameProperty"]);
            Assert.AreEqual(u.IdProperty, jo["IdProperty"]);

            Assert.IsTrue(jo.ContainsKey("EmailsField"));
            if (u.EmailsField == null) Assert.IsNull(jo["EmailsField"]);
            else {
                Assert.IsNotNull(jo["EmailsField"]);
                Verify(u.EmailsField, jo["EmailsField"] as JsonArray);
            }

            Assert.IsTrue(jo.ContainsKey("AddressProperty"));
            if (u.AddressProperty == null) Assert.IsNull(jo["AddressProperty"]);
            else Verify(u.AddressProperty, jo["AddressProperty"] as JsonObject);
        }

        void Verify(Array a, JsonArray ja) {
            Assert.AreEqual(a.Length, ja.Count);
            for (int i = 0; i < a.Length; i++) Assert.AreEqual(a.GetValue(i), ja[i]);
        }
        #endregion

        #region class

        [TestMethod]
        public void FieldsOnly(){
            Address a = new Address();
            a.CountryField = "US";
            a.StateField = "CA";

            JsonObject jo = new JsonObject(Serializer.Serialize(a));
            Verify(a, jo);
        }

        [TestMethod]
        public void PropertyOnly() {
            User u = new User() { IdProperty = 123, NameProperty = "Hello World" };

            JsonObject jo = new JsonObject(Serializer.Serialize(u));
            Verify(u, jo);
        }

        [TestMethod]
        public void NestedObject() {
            User u = new User() {
                AddressProperty = new Address() { CountryField = "US", StateField = "CA" }
            };

            JsonObject jo = new JsonObject(Serializer.Serialize(u));
            Verify(u, jo);
        }


        [TestMethod]
        public void ArrayProperty() {
            User u = new User();
            u.EmailsField = new string[] { "a@b.c", "d@e.f" };

            JsonObject jo = new JsonObject(Serializer.Serialize(u));

            Verify(u, jo);
        }


        [TestMethod]
        public void EmptyArrayProperty() {
            User u = new User();
            u.EmailsField = new string[] { };

            JsonObject jo = new JsonObject(Serializer.Serialize(u));
            Verify(u, jo);
        }

        #endregion

        #region Serialize to JsonArray from arrays

        [TestMethod]
        public void Array_Integers() {
            int[] numbers = new int[] { 1, 2, 3, 4, 5, 0 };
            JsonArray ja = new JsonArray(Serializer.Serialize(numbers));

            for (int i = 0; i < numbers.Length; i++) Assert.AreEqual(numbers[i], ja[i]);
        }

        [TestMethod]
        public void Array_Strings() {
            string[] array = new string[] { "Hello World", "Bye World", "~!@#$%^&*()-=_+,./<>?;:'\"" };
            JsonArray ja = new JsonArray(Serializer.Serialize(array));

            for (int i = 0; i < array.Length; i++) Assert.AreEqual(array[i], ja[i]);
        }

        [TestMethod]
        public void Array_MixedType() {
            object[] array = new object[] { "Hello World", true, false, 12345, 3.14159 };
            string s = Serializer.Serialize(array);

            JsonArray ja = new JsonArray(s);
            for (int i = 0; i < array.Length; i++) Assert.AreEqual(array[i], ja[i]);
        }


        [TestMethod]
        public void NestedArrays() {
            int[][] a0 = new int[][] {
                new int[] {0,1,2},
                new int[] {3,4,5},
                new int[]{6},
                new int[]{}
            };

            JsonArray ja = new JsonArray(Serializer.Serialize(a0));
            for (int i = 0; i < a0.Length; i++) {
                int[] a1 = a0[i];
                JsonArray innerJa = ja[i] as JsonArray;
                Assert.IsNotNull(innerJa);
                for (int j = 0; j < a1.Length; j++) Assert.AreEqual(a1[j], innerJa[j]);
            }
        }


        #endregion


        #region Serialize to JsonArray from List<>


        [TestMethod]
        public void List_Integers() {
            IList<int> list = new List<int> { 1, 2, 3, 4, 5 };
            JsonArray ja = new JsonArray(Serializer.Serialize(list));

            for (int i = 0; i < list.Count; i++) Assert.AreEqual(list[i], ja[i]);
        }

        [TestMethod]
        public void List_Strings() {
            IList<string> list = new List<string>();
            list.Add("Hello World");
            list.Add("早晨");
            list.Add("a@b.c");
            JsonArray ja = new JsonArray(Serializer.Serialize(list));

            for (int i = 0; i < list.Count; i++) Assert.AreEqual(list[i], ja[i]);
        }

        [TestMethod]
        public void List_Classes() {
            IList<User> list = new List<User>();
            list.Add(new User() { IdProperty = 0, NameProperty = "user A" });
            list.Add(new User() { IdProperty = 1, NameProperty = "user B" });
            list.Add(new User() { IdProperty = 2, NameProperty = "user C" });

            JsonArray ja = new JsonArray(Serializer.Serialize(list));
            for (int i = 0; i < list.Count; i++) {
                var jo = (JsonObject)ja[i];
                Verify(list[i], jo);
            }
        }

        #endregion

        #region Serialize from IList
        [TestMethod]
        public void JsonArray() {
            var ja = new JsonArray(new object[] { 1, 2, 3, 4, 5 });
            var s = Serializer.Serialize(ja);

            var ja2 = new JsonArray(s);
            Assert.AreEqual(ja.Count, ja2.Count);
            for (int i = 0; i < ja.Count; i++) Assert.AreEqual(ja[i], ja2[i]);
        }
        #endregion

        #region CustomType
        [TestMethod]
        public void DateTime() {
            DateTime answer = new DateTime(2013, 1, 1);
            var g = new Game() { StartTime = answer, Score = 123 };

            var jo = new JsonObject(Serializer.Serialize(g, new CustomSerializer()));
            DateTime result = Convert.ToDateTime(jo["StartTime"] as string);
            Assert.AreEqual(answer.Ticks, result.Ticks);
        }
        #endregion

        #region Static members
        [TestMethod]
        public void Game_StaticField() {
            DateTime answer = new DateTime(2013, 1, 1);
            var g = new Game() { StartTime = answer, Score = 123 };

            var jo = new JsonObject(Serializer.Serialize(g, new CustomSerializer()));
            Assert.IsFalse(jo.ContainsKey("MinScore"));
        }

        [TestMethod]
        public void Game_StaticProperty() {
            DateTime answer = new DateTime(2013, 1, 1);
            var g = new Game() { StartTime = answer, Score = 123 };

            var jo = new JsonObject(Serializer.Serialize(g, new CustomSerializer()));
            Assert.IsFalse(jo.ContainsKey("StartScore"));
        }
        #endregion
    }
}
